﻿#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include<string.h>
#include<stdlib.h>



//int main()
//{
//	int**a = (int**)malloc(3*sizeof(int*));//申请竖格 
//
//	for (int i = 0; i < 3; i++)//每一行
//	{
//		a[i] = malloc(5 * sizeof(int));//申请每一行中 有几个元素 站几个字节
//	}
//	for (int i = 0; i < 3; i++)
//	{
//		for (int j = 0; j < 5; j++)
//		{
//			printf("%p ", &a[i][j]);
//		}
//		printf("\n");
//	}
//	for (int b = 0; b < 3; b++)
//	{
//		free(a[b]);//先释放 malloc中的malloc申请的内存
//	}
//	free(a);//释放 最后的malloc
//	a = NULL;
//	return 0;
//}

//typedef struct st_type
//{
//	int i;
//	int* p_a;
//}type_a;
//int main()
//{
//	type_a* p = (struct type_a*)malloc(sizeof(type_a));
//	p->i = 100;
//	p->p_a = (int*)malloc(p->i * sizeof(int));
//	//业务处理
//	for (int i = 0; i < 100; i++)
//	{
//		p->p_a[i] = i;
//	}
//	//释放空间 如果 malloc中 又定义了 应该 malloc 得先释放后面那个 在释放最开始定义的那个
//	free(p->p_a);
//	p->p_a = NULL;
//	free(p);
//		p = NULL;
//	return 0;
//}

//typedef struct st_type
//{
//	int i;
//	int a[0];//柔性数组成员
//}type_a;
//int main()
//{	
//	//sizeof 返回的这种结构⼤⼩不包括柔性数组的内存。
//	//printf("%d\n", sizeof(type_a));//输出的是4
//	int i = 0;
//	type_a* p = (type_a*)malloc(sizeof(type_a) + 100 * sizeof(int));
//	//业务处理
//	p->i = 100;
//	for (i = 0; i < 100; i++)
//	{
//		p->a[i] = i;
//	}
//	free(p);
//	return 0;
//}


////C99 中，结构中的最后⼀个元素允许是未知⼤⼩的数组，这就叫做『柔性数组』成员。
//
//typedef struct st_type 
//{
//	int i;
//	int a[0];//柔性数组成员
//}type_a;


//void GetMemory(char* p)
//{
//	// malloc 申请空间 没有机会 导致内存泄漏
//	//对空指针进行解引用操作  会导致操作崩溃
//	p = (char*)malloc(100);
//}
//void Test(void)
//{
//
//	char* str = NULL;
//	GetMemory(str);
//	strcpy(str, "hello world");
//	printf(str);
//}
// 
// 
//char * GetMemory()//正确的方式
//{
//
//	char * p = (char*)malloc(100);
//	return p;
//}
//void Test(void)
//{
//
//	char* str = NULL;
//	str=GetMemory();
//	strcpy(str, "hello world");
//	printf(str);
//	free(str);
//	str = NULL;
//}
// 
// 
//char* GetMemory(void)
//{
//	char p[] = "hello world";
//	return p;
//}
//void Test(void)
//{
//	char* str = NULL;
//	str = GetMemory();
//	printf(str);
//}
//
//void Test(void)
//{
//	char* str = (char*)malloc(100);
//	strcpy(str, "hello");
//	free(str);//释放之后 str为野指针 不为空
//	if (str != NULL)
//	{
//		strcpy(str, "world");//非法访问
//		printf(str);
//	}
//}
//int main()
//{
//	Test();
//	return 0;
//}

//void test()
//{
//	int a = 10;
//	int* p = &a;
//	free(p);//ok?
//	// free 不能对动态内存以外的内存进行释放
//	p = NULL;
//}
//
//
//void test()
//{
//	int i = 0;
//	int* p = (int*)malloc(10 * sizeof(int));
//	if (NULL == p)
//	{
//		exit(EXIT_FAILURE);
//	}
//	for (i = 0; i <= 10; i++)
//	{
//		*(p + i) = i;//当i是10的时候越界访问
//	}
//	free(p);
//}


//int main()
//{
//	//calloc 作用和 malloc 想同
//	//区别 calloc 申请的空间会初始化为0
//	int * p = (int*)calloc(10, sizeof(int));
//	//int* p = (int*)malloc(10, sizeof(int));
//	if (p == NULL)
//	{
//		perror("calloc");
//		return 1;
//	}
//	//使用
//	for (int i = 0; i < 5; i++)
//	{
//		*(p + i) = i;
//	}
//	//realloc 调整申请在堆上内存
//	//如果扩容失败 则返回空指针 
//	//情况1 当申请的内存 原地址 之后的内存不够申请的空间
//	//会在内存中 新找一个空间 把所有的东西搬到 新开辟的空间 会改变起始地址
//	// 旧的空间会被 直接自动释放掉
//	//情况2 如果申请的内存 原地址 后面够申请空间 
//	// 那么会直接追加
//	int * prt =realloc(p,40);
//	//realloc(NULL,40)=malloc(40) 当realloc 函数 第一个参数为空指针的时候 作用相当于 malloc
//	if (prt != NULL)//如果不为空指针的时候 在扩容
//	{
//		p = prt;
//		prt = NULL;//设置为空指针 
//	}
//	//释放
//	free(p);
//	//不能释放 prt 会吧p也释放掉
//	p = NULL;
//	return 0;
//}

//int main()
//{
//    union
//    {
//        short k;
//        char i[2];
//    }*s, a;
//    s = &a;
//    s->i[0] = 0x39;
//    s->i[1] = 0x38;
//    printf("%x\n", a.k);//3839 因为是小端字节存储 从右向左存
//    return 0;
//}


////动态内存是在堆区上 申请的
//int main()
//{
//	//申请十个整形的空间
//	//malloc 用来申请内存空间的库函数
//	//malloc 是在堆区 申请内存
//	int * p =malloc(10 * sizeof(int));
//	if (p == NULL)//开辟失败
//	{
//		perror("malloc");//perror 打印错误信息
//		return 1;
//	}
//	//开辟成功 使用空间
//	int i = 0;
//	for (i = 0; i < 10; i++)
//	{
//		*(p + i) = i;
//	}
//	for (i = 0; i < 10; i++)
//	{
//		printf("%d ", p[i]);
//	}
//	//申请完需要回收空间
//	//free 回收
//	//自己不释放的时候 程序结束后 也会由操作系统回收
//	//free 只能释放 动态内存申请的空间
//	free(p);//释放p 指向的地址 释放之后 p为野指针
//	p = NULL;//栓起 野指针
//	return 0;
//}


//int main()
//{
//	int val = 20;//在栈空间上开辟四个字节 但是创建后不能改变
//	char arr[10] = { 0 };//在栈空间上开辟10个字节的连续空间 但是创建后不能改变
//
//	return 0;
//}